feat: add read-only Gateway TUI - #1956
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## refactor #1956 +/- ##
============================================
+ Coverage 96.79% 96.88% +0.08%
============================================
Files 306 322 +16
Lines 17051 17634 +583
============================================
+ Hits 16505 17085 +580
- Misses 546 549 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
e5fda21 to
c710a7a
Compare
Gateway read-only TUI demoRecorded with the real TUI components and synthetic Gateway/Connector data. No AWS account or credential metadata is included. |
jariy17
left a comment
There was a problem hiding this comment.
Could be a follow up pr? It's pretty god
| const items: TargetSummary[] = []; | ||
| let token = nextToken; | ||
|
|
||
| while (true) { |
There was a problem hiding this comment.
▎ Flagging a second issue in this block, separate from the unbounded scan.
▎
▎ Early stop. const full = maxResults === undefined ? items.length > 0 : .... On the no-maxResults path, items.length > 0 returns after the first Target page that yields any connector. So a Gateway with 30 connectors can return just the 2 that
▎ landed in page 1. Every other list returns a full service page. This one doesn't.
▎
▎ Wrong token. return { ...response, items } returns response.nextToken, which is a ListGatewayTargets token. It means more Targets remain, not more Connectors. The TUI surfaces a "more →" affordance whenever a token is present, so a user can
▎ page forward into an empty Connector screen while connectors still exist deeper in the Target stream.
▎
▎ Fix: treat the undefined case like the numeric one. Fill to a default page size instead of stopping at the first hit, so the page and its token stay connector-aligned. At minimum, add a comment that the token paginates Targets, not
▎ Connectors.
There was a problem hiding this comment.
Fixed in 24f49f8. Connector discovery is now capped at 101 Target pages (one above the documented default 100-target Gateway quota) and throws the merged ResultTruncationError instead of scanning indefinitely or returning partial results. I added an ever-advancing-token regression test that verifies the cap.
There was a problem hiding this comment.
Fixed in 24f49f8. An omitted maxResults now fills a 100-row logical Connector page instead of stopping at the first hit. After a page fills, Core looks ahead and returns the service token used to fetch the first later Target page known to contain a Connector; if none exists, nextToken is omitted. This keeps AWS tokens, avoids buffered/custom token state, and prevents a false "more" page. Added focused tests for default filling, aligned lookahead, and exhausted lookahead.
c710a7a to
24f49f8
Compare
| import { PaginatedTablePicker } from "./PaginatedTablePicker"; | ||
| import type { DataTableColumn } from "./ui/data-table"; | ||
|
|
||
| interface GatewayRuleRow extends Record<string, unknown> { |
There was a problem hiding this comment.
wow, all these common components make this so easy to read!
| let token = nextToken; | ||
| let filling = true; | ||
|
|
||
| for (let page = 0; page < MAX_CONNECTOR_TARGET_PAGES; page++) { |
There was a problem hiding this comment.
does the api not support server side filtering? if so that feels like a major gap, especially if this is a common customer use-case.
There was a problem hiding this comment.
It doesn't support it at the moment. We could probably request Gateway do it. But I wonder if since they haven't, maybe it really isn't that useful to the customer...
This could be removed for just gateway target list/get. I think that would make sense. But we wanted to separate connector for CUD because it is helpful for containing flags to specific use cases.
| ["Rule list", ["gateway", "rule", "list"]], | ||
| ] as const)("opens the TUI for a bare %s command", async (_label, args) => { | ||
| await expect(run([...args])).rejects.toThrow( | ||
| "interactive mode requires a TTY on stdin and stdout", |
There was a problem hiding this comment.
is there a way to make this test more explicit? Right now we're relying on the behavior that tty is required for this test to work.
There was a problem hiding this comment.
Good call. Fixed in 9d530a5. The Gateway test now compiles the real command tree and asserts isTuiCommandSupported directly for every read path, plus false for each CLI-only create path. The create cases still assert normal handler validation, while the generic TTY dispatch behavior remains owned by the middleware unit test.

Summary
get/listgetroutes redirecting through the corresponding list flowGatewayClient, with CLI and TUI consumers delegating throughCoreGatewayClientmaxResults, cap discovery at 101 Target pages, and use lookahead sonextTokenis returned only when another Connector existssupportedTuiCommandsso read commands enter the TUI while bare CLI-only create commands run normal validationTesting
bun test src/handlers/gateway/gateway.test.tsx src/handlers/gateway/gateway.screen.test.tsx src/handlers/gateway/gateway.fixture.test.tsx src/core/gateway.test.ts src/components/ui/data-table/columnWidths.test.ts(88pass)bun test --coverage --coverage-reporter=text(1081pass;93.73%functions,97.88%lines)bun run typecheckbun run lint:checkbun run format:checkbun run buildnpm pack --ignore-scriptsget/listleaves (12/12)100x30, confirming Gateway and Connector menus expose read-only commands onlyListGatewayTargetstoken created withmaxResults=2in a request withmaxResults=1, returning the next distinct TargetRECORD=1 AWS_PROFILE=e2e-test bun test src/handlers/gateway/gateway.fixture.test.tsx -t 'lists Gateway Connectors'The full source run retains seven local
src/io/exec.test.tsfailures plus three associated errors on files byte-identical toorigin/refactor.